#ifndef _ACTION_H_
#define _ACTION_H_

#include "daemon.h"
#include "disk.h"
#include "filesystemerror.h"
#include "sendererror.h"

namespace Avd {

/**
 * Abstract class Action.
 */

class Action {
public:
	/**
	 * An action can execute something using the daemon.
	 * @param daemon
	 */
	virtual void doIt(Daemon* daemon) = 0;
protected:
	Action() { }
};

/**
 * Empty Action.
 */

class NoAction : public Action {
public:
	/**
	 * Just do nothing.
	 * @param daemon
	 */
	NoAction() { }
	void doIt(Daemon*) { }
};

/**
 * Abstract file Action.
 */

class FileAction : public Action {
public:
	/**
	 * Execute something using a \a daemon and a \a file.
	 * @param daemon
	 */
	virtual void doIt(Daemon* daemon) throw(FileSystemError, SenderError) = 0;
protected:
	FileAction(const File& file) : file(file) { }

	File file;
};


/**
 * Download FileAction.
 */

class DownloadFileAction : public FileAction {
public:
	DownloadFileAction(const File& file) : FileAction(file) { }
	/**
	 * Send an askDownload to the \a daemon.
	 * @throws SenderError Could not send the download message.
	 * @param daemon
	 */
	void doIt(Daemon* daemon) throw(SenderError) {
		daemon->askDownload(file);
	}
};

/**
 * Delete FileAction.
 */

class DeleteFileAction : public FileAction {
public:
	DeleteFileAction(const File& file) : FileAction(file) { }

	/**
	 * Send an askDelete to the \a daemon.
	 * @throws SenderError Could not send the delete message.
	 * @param daemon
	 */
	void doIt(Daemon* daemon) throw(SenderError) {
		daemon->askDelete(file);
	}
};

/**
 * Delete local FileAction.
 */

class DeleteLocalFileAction : public FileAction {
public:
	DeleteLocalFileAction(const File& file) : FileAction(file) { }

	/**
	 * Remove file from filesystem.
	 * @throws FileSystemError Could not remove the \a file from filesystem.
	 * @param daemon
	 */
	void doIt(Daemon* daemon) throw(FileSystemError) {
		daemon->getDisk()->remove(file);
	}
};

/**
 * Update FileAction.
 */

class UpdateFileAction : public FileAction {
public:
	UpdateFileAction(const File& file) : FileAction(file) { }

	/**
	 * Send an askUpload to the \a daemon.
	 * @throws FileSystemError Could not upload the \a file to server.
	 * @throws SenderError Could not send the upload message.
	 * @param daemon
	 */
	void doIt(Daemon* daemon) throw(FileSystemError, SenderError) {
		daemon->askUpload(file);
	}
};


/**
 * Folder Action
 */

class FolderAction : public Action {
public:

	/**
	 * Execute something using a \a daemon and a \a folder.
	 * @param daemon
	 */
	virtual void doIt(Daemon* daemon) throw(FileSystemError, SenderError) = 0;
protected:
	FolderAction(const Folder& folder) : folder(folder) { }

	Folder folder;
};

/**
 * Create FolderAction
 */

class CreateFolderAction : public FolderAction {
public:
	CreateFolderAction(const Folder& folder) : FolderAction(folder) { }

	/**
	 * Send an askCreateFolder to the \a daemon.
	 * @throws SenderError Could not send the create folder message.
	 * @param daemon
	 */
	void doIt(Daemon* daemon) throw(SenderError) {
		daemon->askCreateFolder(folder);
	}
};

/**
 * Create local FolderAction
 */

class CreateLocalFolderAction : public FolderAction {
public:
	CreateLocalFolderAction(const Folder& folder) : FolderAction(folder) { }

	/**
	 * Create a folder on filesystem.
	 * @throws FileSystemError Could not create the \a folder on filesystem.
	 * @throws SenderError Could not send the askList message to the new folder.
	 * @param daemon
	 */
	void doIt(Daemon* daemon) throw(FileSystemError, SenderError) {
		daemon->getDisk()->create(folder);
		daemon->askList(folder);
	}
};

/**
 * Delete FolderAction
 */

class DeleteFolderAction : public FolderAction {
public:
	DeleteFolderAction(const Folder& folder) : FolderAction(folder) { }

	/**
	 * Send an askDelete to the \a daemon.
	 * @throws SenderError Could not send the delete message.
	 * @param daemon
	 */
	void doIt(Daemon* daemon) throw(SenderError) {
		daemon->askDelete(folder);
	}
};

/**
 * Delete local FolderAction
 */

class DeleteLocalFolderAction : public FolderAction {
public:
	DeleteLocalFolderAction(const Folder& folder) : FolderAction(folder) { }

	/**
	 * Remove folder from filesystem.
	 * @throws FileSystemError Could not remove the \a folder from filesystem.
	 * @param daemon
	 */
	void doIt(Daemon* daemon) throw(FileSystemError) {
		daemon->getDisk()->remove(folder);
	}
};


}

#endif // _ACTION_H_
